package org.gjy.m8.concurrent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-06-30 16:02:47
 */
public class ConditionTest {
    private static final Logger log = LoggerFactory.getLogger(ConditionTest.class);

    private static final Lock LOCK = new ReentrantLock(true);

    private static final Condition ca = LOCK.newCondition();
    private static final Condition cb = LOCK.newCondition();
    private static final Condition cc = LOCK.newCondition();
    private final AtomicInteger state = new AtomicInteger(0);
    private static final Integer printSize = 5;

    /**
     * A B C 交替打印
     */
    public static void main(String[] args) {

        ThreadPoolExecutor pool = ThreadPoolUtil.getDefaultPool();

        ConditionTest test = new ConditionTest();
        pool.submit(test::printA);
        pool.submit(test::printB);
        pool.submit(test::printC);

        ThreadPoolUtil.shutdown(pool);
    }

    public void printA() {
        LOCK.lock();
        try {
            for (int i = 0; i < printSize; i++) {
                while (state.get() != 0) {
                    ca.await();
                }
                log.info("A");
                state.compareAndSet(0, 1);
                cb.signal();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }

    public void printB() {
        LOCK.lock();
        try {
            for (int i = 0; i < printSize; i++) {
                while (state.get() != 1) {
                    cb.await();
                }
                log.info("B");
                state.compareAndSet(1, 2);
                cc.signal();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }

    public void printC() {
        LOCK.lock();
        try {
            for (int i = 0; i < printSize; i++) {
                while (state.get() != 2) {
                    cc.await();
                }
                log.info("C");
                state.compareAndSet(2, 0);
                ca.signal();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }

}
